#pragma once
#include "InetAddr.hpp"
#include "Common.hpp"
#include"ThreadPool.hpp"
  #include <sys/types.h>
       #include <sys/wait.h>

namespace kzz
{
    //  远程执行命令模块，这里的传入函数应该是执行命令，
    // 要知道是谁要执行命令，执行什么命令，不需要知道文件描述符
     //using _func_t = std::function<void(int sockfd, InetAddr &_addr)>;

    // 翻译模块 ，不需要知道文件描述符，知道单词和客户端就行
    using _func_t = std::function<std::string(const std::string &buffer, InetAddr &_addr)>;

    // using _func_t = std::function<void(int sockfd, const std::string &word, InetAddr &_addr)>;
    class TcpServer : public NoCopy
    {
    public:
        TcpServer(uint16_t port, _func_t func)
            : _listensockfd(-1), _port(port), _isrunning(false), _func(func)
        {
        }
        // TcpServer(const kzz::TcpServer &) = default;
        // TcpServer(kzz::TcpServer &&) = default;

        void Init()
        {
            _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (_listensockfd < 0)
            {
                kzz::LOG(LogLevel::ERROR) << "listen server创建套接字失败";
                exit(LISTEN_ERR);
            }

            kzz::LOG(LogLevel::ERROR) << "listen server socket success,sockfd:" << _listensockfd;

            kzz::InetAddr local(_port);
            // struct sockaddr_in local;

            int n = bind(_listensockfd, local.Addr(), local.Len());

            if (n != 0)
            {
                kzz::LOG(LogLevel::ERROR) << "bind error";
                exit(BIND_ERR);
            }
            kzz::LOG(LogLevel::ERROR) << "bind success";
            int l = listen(_listensockfd, SOMAXCONN);
            if (l < 0)
            {
                kzz::LOG(LogLevel::ERROR) << "listen error";
                exit(LISTEN_ERR);
            }
            kzz::LOG(LogLevel::ERROR) << "listen success";
        }
        //服务
        void Service(int client_fd, InetAddr &client_addr)
        {
             while (true)
                            {
                                char buffer[1024];
                                int s = read(client_fd, buffer, sizeof(buffer));

                                if (s < 0)
                                {
                                    kzz::LOG(LogLevel::DBUGER) << "read fail";
                                    exit(READ_ERR);
                                }
                                if (s > 0)
                                {
                                    kzz::LOG(LogLevel::DBUGER) << "服务器收取数据成功,客户端为" << client_addr.Ip().c_str() << ' '
                                                               << client_addr.Port() << "数据为: " << buffer;

                                    // 翻译模块
                                    // 开始执行传入的func,对数据进行处理
                                    // 这里应该让子进程去执行，要不然就只能和一个客户端交互，
                                    // 如果让父进程继续这里的代码，执行完这两句，
                                    // 就会继续accept，无法完成当前这个客户端的其他翻译任务

                                    std::string ret = _func(buffer, client_addr);
                                    write(client_fd, ret.c_str(), ret.size());
                                }
                            }
        }
        // class ThreadData
        // {
        //     public:
        //     ThreadData(int fd,const InetAddr& addr,TcpServer* tser)
        //     :_client_fd(fd)
        //     ,_client_addr(addr)
        //     ,_tser(tser)
        //     {}

        //     public:
        //     int _client_fd;
        //     InetAddr _client_addr;
        //     TcpServer* _tser;
        // };
        // void* Routine(void* argv)
        // {
        //     ThreadData* data=(ThreadData*)argv;
        //    data->_tser->Service(data->_client_fd,data->_client_addr);
        //     return nullptr;
        // }

        // 服务器接受数据，然后处理完发回去
        void Start()
        {
            _isrunning = true;
            while (_isrunning)
            {
                // 定义socke地址结构体,用来保存客户端的IP和端口号
                // kzz::InetAddr client_addr;

                char buffer[1024];
                sockaddr_in client;
                socklen_t len = sizeof(client);
                int client_fd = accept(_listensockfd, (sockaddr *)&client, &len);
                kzz::InetAddr client_addr(client);
                if (client_fd >= 0)
                {
                    kzz::LOG(LogLevel::ERROR) << "accept success,sockfd:" << client_fd;
                    ////vinson2:多线程版
                    // Thread th([this,&client_fd,&client_addr](){
                    //     Service(client_fd,client_addr);
                    // });
                    // //th.detach();
                    // th.Start();
                    // //th.detach();
                    // th.Join();

                    //vision3: 线程池版
                    //来一个客户端就入池，把这个任务传给池
                //     using task_t=std::function<void()>;
                //    kzz::ThreadPool<task_t> *tp= kzz::ThreadPool<task_t>::GetInstance();
                //    tp->Start();
                //     tp->Equeue([this,&client_fd,&client_addr](){
                //         Service(client_fd,client_addr);
                //     });

                    

                    //   vinson1：多进程版本
                    int pid = fork();
                    if (pid == 0)
                    {
                        // 子进程
                        //  接受客户端成功,开始接受客户端的传入数据
                        // 继续生成孙子进程
                        //关闭不需要的文件描述符
                        close(_listensockfd);
                        int two_id=fork();
                        if (two_id==0)
                        {
                            //孙子进程
                            Service(client_fd,client_addr);
                        }
                        else if(two_id<0)
                        {
                             kzz::LOG(LogLevel::DBUGER) << "two fork fail";
                        exit(FORK_ERR);
                        }
                        else
                        {
                            //子进程退出
                            kzz::LOG(LogLevel::DBUGER) << "two fork success";
                            exit(OK);
                        }
                    }
                    else if (pid < 0)
                    {
                        kzz::LOG(LogLevel::DBUGER) << "fork fail";
                        exit(FORK_ERR);
                    }
                    else
                    {
                        // 父进程
                        // 需要等待子进程，所以让孙子进程去干活，子进程直接wait，孙子变成孤儿，一号进程收养
                        //关闭不需要的文件描述符，不需要客户端的文件描述符了
                        close(client_fd);
                        int rid=wait(&pid);
                        (void)rid;
                    }
                }
                // 这里返回值不会等于0，因为有默认的输入输出错误，除非自己关了
                else
                {
                    // 接受失败
                    kzz::LOG(LogLevel::ERROR) << "accept error";
                    exit(ACCEPT_ERR);
                }
            }
        }

    private:
        int _listensockfd;
        uint16_t _port;
        _func_t _func;
        bool _isrunning;
    };
}